#include "LEX.h"
#include <iostream>
int LEX::next_char()
{
    if (this->in_buf == this->in_buf_empty)return this->get_char();   
    int back = this->in_buf;
    this->in_buf = this->in_buf_empty;
    return back;
}

void LEX::back_char(int back_up_char)
{
    this->in_buf = back_up_char;
}

int LEX::lexer()
{
    this->buffer = std::string();
    if (this->get_char == nullptr || this->eof == nullptr)return TOK::ERR;
    if (this->eof())return TOK::SCANEOF;
    int ch = this->next_char();
    while (isspace(ch))ch = this->next_char();
    switch (ch)
    {
    case '(':return TOK::LPAREN;
    case ')':return TOK::RPAREN;
    case '+':return TOK::PLUS;
    case '-':return TOK::MINUS;
    case '!':
        ch = this->next_char();
        if (ch == '=')
            return TOK::NE;
        else
        {
            back_char(ch);
            return TOK::NOT;
        }
    case '*':return TOK::MUL;
    case '/':return TOK::DIV;
    case '%':return TOK::MOD;
    case '>':
        ch = this->next_char();
        if (ch == '=')
            return TOK::GE;
        else
        {
            back_char(ch);
            return TOK::GT;
        }
    case '<':
        ch = this->next_char();
        if (ch == '=')
            return TOK::LE;
        else
        {
            back_char(ch);
            return TOK::LT;
        }
    case '=':
        ch = this->next_char();
        if (ch == '=')
            return TOK::EQ;
        if (ch != '=')
        {
            back_char(ch);
            return TOK::ASSIGN;
        }
    case '&':
        ch = this->next_char();
        if (ch == '&')
            return TOK::LAND;
        if (ch != '&')
        {
            back_char(ch);
            return TOK::BAND;
        }
    case '|':
        ch = this->next_char();
        if (ch == '|')
            return TOK::LOR;
        if (ch != '|')
        {
            back_char(ch);
            return TOK::BOR;
        }
    case -1:
        return TOK::SCANEOF;
    default:
        if (isalpha(ch) || ch == '_')
        {
            do
            {
                this->buffer.push_back(ch);
                if (this->eof())return TOK::INDENTIFIER;
                ch = next_char();
            } while (isalnum(ch) || ch == '_');
            this->back_char(ch);
            return TOK::INDENTIFIER;
        }
        else if (isdigit(ch))
        {
            do
            {
                this->buffer.push_back(ch);
                if (this->eof())return TOK::NUMBER;
                ch = next_char();
            } while (isdigit(ch));
            this->back_char(ch);
            return TOK::NUMBER;
        }
        else
        {
            std::cerr << "lexical error:unexpected character \'" << char(ch) << "\'" << std::endl;
            return TOK::ERR;
        }
    case ';':return TOK::SEMICOLON;
    }
}

LEX::LEX()
{
    this->token_buffer = TOK::UNDEFINED;
    this->in_buf = this->in_buf_empty;
    this->get_char = nullptr;
    this->eof = nullptr;
}

LEX::LEX(int(*n_c)(), bool(*eof)())
{
    this->token_buffer = TOK::UNDEFINED;
    this->in_buf = this->in_buf_empty;
    this->get_char = n_c;
    this->eof = eof;
}


std::string LEX::get_buffer()
{
    return this->buffer;
}

int LEX::next_token()
{
    if (this->token_buffer == TOK::UNDEFINED)
        this->token_buffer = this->lexer();
    return this->token_buffer;
}

void LEX::match(int want)
{
    if (this->next_token() != want)
    {
        std::cerr << "failed to match token" << std::endl;
        exit(-1);
    }
    this->token_buffer = TOK::UNDEFINED;
}
